<template>
  <a-modal v-if="mode == 'dialog'" v-bind="$attrs" :width="width" :closable="closable" :confirm-loading="confirmLoading"
    :visible="visible" :destroy-on-close="destroyOnClose" :mask-closable="maskClosable" :keyboard="keyboard" @ok="(v) => {
        $emit('ok', v)
      }
      " @cancel="(v) => {
      $emit('cancel', v)
    }
    ">
    <template v-for="item in renderArr" #[item]="scope">
      <slot :name="item" :scope="scope" v-bind="scope || {}"></slot>
    </template>
    <template #title>
      <template v-if="draggable">
        <div ref="modalTitleRef" style="width: 100%; cursor: move">{{ title }}</div>
      </template>
      <template v-else-if="title != null">
        {{ title }}
      </template>
      <template v-else>
        <slot name="title" />
      </template>
    </template>
    <template v-if="draggable" #modalRender="{ originVNode }">
      <div :style="transformStyle">
        <component :is="originVNode" />
      </div>
    </template>
  </a-modal>
  <template v-else>
    <div v-if="visible" style="
        height: 100%;
        width: 100%;
        z-index: 1000;
        position: absolute;
        left: 0px;
        top: 0px;
        background-color: #fff;
        padding: 10px;
      ">
      <slot name="header"></slot>
      <span style="float: right; margin-top: 3px; margin-bottom: 10px">
        <s-button icon="left-outlined" @click="close">返回</s-button>
      </span>
      <div style="widht: 100%; height: calc(100% - 64px); margin-top: 34px">
        <slot></slot>
      </div>
      <div style="float: right; margin-top: 3px; margin-bottom: 10px">
        <slot name="footer"></slot>
      </div>
    </div>
  </template>
</template>
<script>
import {
  defineComponent,
  ref,
  computed,
  watch,
  watchEffect,
  reactive,
  useSlots,
  toRefs,
  onUnmounted
} from 'vue'
import { useDraggable } from '@vueuse/core'
export default defineComponent({
  name: 'SModal',
  props: {
    draggable: {
      type: Boolean,
      required: false,
      default: () => {
        return true
      }
    },
    okText: {
      type: String,
      required: false,
      default: '确定'
    },
    width: {
      type: String,
      required: false
    },
    confirmLoading: {
      type: Boolean,
      required: false,
      default: () => {
        return false
      }
    },
    closable: {
      type: Boolean,
      required: false,
      default: () => {
        return true
      }
    },
    mode: {
      type: String,
      default: 'dialog'
    },
    keyboard: {
      type: Boolean,
      required: false,
      default: () => {
        return false
      }
    },
    maskClosable: {
      type: Boolean,
      required: false,
      default: () => {
        return false
      }
    },
    destroyOnClose: {
      type: Boolean,
      required: false,
      default: () => {
        return true
      }
    },
    title: {
      type: String,
      required: false
    },
    visible: {
      type: Boolean,
      required: false,
      default: () => {
        return false
      }
    }
  },
  emits: ['ok', 'cancel', 'update:visible'],
  setup(props, { emit }) {
    watch(
      () => props.visible,
      (newVal, oldVal) => {
        if (newVal == false) {
          transformX.value = 0
          transformY.value = 0
        }
      }
    )
    const modalTitleRef = ref(null)
    const slots = useSlots()
    const renderArr = Object.keys(slots).filter((key) => {
      return key != 'title' && key != 'modalRender' && key != 'title'
    })
    const data = reactive({
      renderArr
    })
    const startX = ref(0)
    const startY = ref(0)
    const startedDrag = ref(false)
    const transformX = ref(0)
    const transformY = ref(0)
    const preTransformX = ref(null)
    const preTransformY = ref(null)
    const dragRect = ref({ left: 0, right: 0, top: 0, bottom: 0 })
    const { x, y, isDragging } = useDraggable(modalTitleRef)
    watch([x, y], () => {
      if (!startedDrag.value) {
        startX.value = x.value
        startY.value = y.value
        const bodyRect = document.body.getBoundingClientRect()
        const titleRect = modalTitleRef.value.getBoundingClientRect()
        dragRect.value.right = bodyRect.width - titleRect.width
        dragRect.value.bottom = bodyRect.height - titleRect.height
        preTransformX.value = transformX.value
        preTransformY.value = transformY.value
      }
      startedDrag.value = true
    })
    watch(isDragging, () => {
      if (!isDragging) {
        startedDrag.value = false
      }
    })
    watchEffect(() => {
      if (startedDrag.value) {
        transformX.value =
          preTransformX.value +
          Math.min(Math.max(dragRect.value.left, x.value), dragRect.value.right) -
          startX.value
        transformY.value =
          preTransformY.value +
          Math.min(Math.max(dragRect.value.top, y.value), dragRect.value.bottom) -
          startY.value
      }
    })
    const transformStyle = computed(() => {
      return {
        transform: `translate(${transformX.value}px, ${transformY.value}px)`
      }
    })
    const close = () => {
      emit('update:visible', false)
    }
    return {
      close,
      transformStyle,
      modalTitleRef,
      ...toRefs(data)
    }
  }
})
</script>
